package com.bs.web.filter;

import cn.hutool.json.JSONUtil;
import com.bs.service.IAuthService;
import com.bs.util.CorsUtil;
import com.bs.vo.RestResultVo;
import io.swagger.models.HttpMethod;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.PathContainer;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.cors.*;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 说明：
 *
 * @author 琪
 * @since 2025/5/7 22:31
 */
@WebFilter(filterName = "authFilter", urlPatterns = "/*")
@Slf4j
public class AuthFilter implements Filter {

    @Autowired
    private IAuthService authService;

    private Integer tokenExpireCode = 10000;

    @Value("${auth.exclude:}")
    private List<String> excludeConfig;
    private final List<PathPattern> whitelistPatterns = new ArrayList<>();
    private final PathPatternParser pathPatternParser = new PathPatternParser();

    List<String> excludeUrls = new ArrayList<>();

    @PostConstruct
    public void init() {
        excludeUrls.add("/login");
        excludeUrls.add("/register");
        excludeUrls.add("/logout");
        excludeUrls.add("/swagger");
        excludeUrls.add("/v2/api-docs");
        excludeUrls.add("/webjars");
        excludeUrls.add("/swagger-resources");
        excludeUrls.add("/doc.html");
        excludeUrls.add("/favicon.ico");
        excludeUrls.add("/error");
        // 添加其他需要排除的URL
        excludeUrls.add("/auth");
        // 文件接口
        excludeUrls.add("/file");
        for (String exclude : excludeConfig) {
            whitelistPatterns.add(pathPatternParser.parse(exclude));
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String uri = request.getRequestURI();
        String method = request.getMethod();
        log.info("[{}][{}] 收到请求", method, uri);
        // 强制所有接口使用utf-8编码
        response.setCharacterEncoding("UTF-8");
        try {
            myFilter(servletRequest, servletResponse, filterChain);
        } catch (Exception e) {
            // 为认证失败添加cors允许跨域
            CorsUtil.addCors(request, response);
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());

            String message = e.getMessage();
            log.error("[{}][{}] 接口调用异常, error: {}", method, uri, message);
            RestResultVo<Object> resultVo = RestResultVo.failed(message);
            resultVo.setCode(tokenExpireCode);
            response.getWriter().write(JSONUtil.toJsonStr(resultVo));
        }
    }

    private void myFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
        // 获取request
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        // 获取请求的URL
        String requestUri = request.getRequestURI();
        String method = request.getMethod();
        if (HttpMethod.OPTIONS.name().equals(method)) {
            // options直接放行，继续执行请求
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        // 检查请求是否需要排除
        for (String excludeUrl : excludeUrls) {
            if (requestUri.contains(excludeUrl)) {
                // 如果请求需要排除，继续执行请求
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
        }
        // 检查配置文件排除
        PathContainer path = PathContainer.parsePath(requestUri);
        for (PathPattern whitelistPattern : whitelistPatterns) {
            if (whitelistPattern.matches(path)) {
                // 如果请求需要排除，继续执行请求
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
        }

        // 从请求头中获取token
        String token = request.getHeader("token");
        // 检查token是否有效
        if (authService.getLoginUser() != null) {
            // 如果token有效，继续执行请求
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
}